package com.gitee.easyopen;

import java.util.Locale;
import java.util.Map;

import javax.servlet.ServletContext;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;

import org.springframework.context.ApplicationContext;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import org.springframework.web.context.support.GenericWebApplicationContext;

import com.auth0.jwt.interfaces.Claim;
import com.gitee.easyopen.auth.Oauth2Manager;
import com.gitee.easyopen.auth.OpenUser;
import com.gitee.easyopen.bean.Consts;
import com.gitee.easyopen.bean.RequestMode;
import com.gitee.easyopen.exception.ApiException;
import com.gitee.easyopen.jwt.JwtService;
import com.gitee.easyopen.message.Errors;
import com.gitee.easyopen.session.SessionManager;

/**
 * 应用上下文,方便获取信息
 * 
 * @author tanghc
 *
 */
public class ApiContext {
    private static ThreadLocal<ApiParam> param = new InheritableThreadLocal<>();
    private static ThreadLocal<HttpServletRequest> request = new InheritableThreadLocal<>();
    private static ThreadLocal<OpenUser> tokenUser = new InheritableThreadLocal<>();
    private static ThreadLocal<Map<String, Claim>> jwtData = new InheritableThreadLocal<>();
    private static ThreadLocal<RequestMode> requestMode = new InheritableThreadLocal<>();

    private static ApplicationContext applicationContext;
    private static ServletContext servletContext;

    private static ApiConfig apiConfig;

    public static String getRandomKey() {
        return (String) getSession().getAttribute(Consts.RANDOM_KEY_NAME);
    }

    public static void setRequestMode(RequestMode mode) {
        requestMode.set(mode);
    }

    public static String decryptAES(String value) {
        String randomKey = getRandomKey();
        try {
            Encrypter encrypter = apiConfig.getEncrypter();
            return encrypter.aesDecryptFromHex(value, randomKey);
        } catch (Exception e) {
            throw Errors.ERROR_PARAM.getException();
        }
    }

    /**
     * 是否加密模式
     */
    public static boolean isEncryptMode() {
        RequestMode mode = requestMode.get();
        if (mode == null) {
            return false;
        }
        return RequestMode.ENCRYPT == mode;
    }

    /**
     * 创建JWT
     * 
     * @param appKey
     * @param data
     * @return
     */
    public static String createJwt(Map<String, String> data) {
        Assert.notNull(apiConfig, "apiConfig尚未初始化");
        JwtService jwtService = apiConfig.getJwtService();
        return jwtService.createJWT(data);
    }

    /**
     * 返回jwt数据,没有返回null
     * 
     * @return
     */
    public static Map<String, Claim> getJwtData() {
        return jwtData.get();
    }

    public static void setJwtData(Map<String, Claim> data) {
        jwtData.set(data);
    }

    /**
     * 获取accessToken对应的用户
     * 
     * @return
     */
    public static OpenUser getAccessTokenUser() {
        OpenUser user = tokenUser.get();
        if (user != null) {
            return user;
        }
        String accessToken = getSessionId();
        if (StringUtils.isEmpty(accessToken)) {
            throw new ApiException(ParamNames.ACCESS_TOKEN_NAME + "不存在");
        }
        try {
            Oauth2Manager manager = apiConfig.getOauth2Manager();
            OpenUser openUser = manager.getUserByAccessToken(accessToken);
            ApiContext.setAccessTokenUser(openUser);
            return openUser;
        } catch (Exception e) {
            throw new ApiException(e);
        }
    }

    public static void setAccessTokenUser(OpenUser openUser) {
        tokenUser.set(openUser);
    }

    /**
     * 获取HttpServletRequest
     * 
     * @return HttpServletRequest
     */
    public static HttpServletRequest getRequest() {
        HttpServletRequest req = request.get();
        if (req == null) {
            req = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        }
        return req;
    }

    /**
     * 返回默认的HttpServletRequest.getSession();
     * 
     * @return
     */
    public static HttpSession getSession() {
        HttpServletRequest req = getRequest();
        if (req == null) {
            return null;
        } else {
            return req.getSession();
        }
    }

    /**
     * 返回自定义的session,被SessionManager管理
     * 
     * @return
     */
    public static HttpSession getManagedSession() {
        String sessionId = getSessionId();
        if (sessionId != null) {
            SessionManager sessionManager = apiConfig.getSessionManager();
            return sessionManager.getSession(sessionId);
        } else {
            return null;
        }
    }

    /**
     * 获取登陆的token
     * 
     * @return 没有返回null
     */
    public static String getSessionId() {
        ApiParam apiParam = getApiParam();
        if (apiParam == null) {
            return null;
        }
        return apiParam.fatchAccessToken();
    }

    public static void setRequest(HttpServletRequest req) {
        request.set(req);
    }

    /**
     * 获取本地化
     * 
     * @return Locale
     */
    public static Locale getLocal() {
        HttpServletRequest req = getRequest();
        if (req == null) {
            return Locale.SIMPLIFIED_CHINESE;
        }
        return req.getLocale();
    }

    public static void setApiParam(ApiParam apiParam) {
        param.set(apiParam);
    }

    /**
     * 获取系统参数
     * 
     * @return 返回ApiParam
     */
    public static ApiParam getApiParam() {
        return param.get();
    }

    public static ApiConfig getApiConfig() {
        return apiConfig;
    }

    public static void setApiConfig(ApiConfig apiConfig) {
        ApiContext.apiConfig = apiConfig;
    }

    public static ApplicationContext getApplicationContext() {
        return applicationContext;
    }

    public static void setApplicationContext(ApplicationContext applicationContext) {
        ApiContext.applicationContext = applicationContext;
        if (applicationContext instanceof GenericWebApplicationContext) {
            servletContext = ((GenericWebApplicationContext) applicationContext).getServletContext();
        }
    }

    public static ServletContext getServletContext() {
        if (servletContext != null) {
            return servletContext;
        } else {
            ServletContext ctx = null;
            HttpSession session = getSession();
            if (session != null) {
                ctx = session.getServletContext();
            }
            return ctx;
        }
    }

}
